/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pr2.cruce;

import java.util.ArrayList;
import java.util.List;
import pr2.cromosoma.CromosomaPVC;

/**
 *
 * @author Gonzalo Ortiz Jaureguizar (gortiz at software.imdea.org)
 */
public class CodificacionOrdinal extends EstrategiaCruce<CromosomaPVC> {
    
    /**
     * La lista dinamica, que sera la estandar (0,1,2, ... size-1)
     */
    private final ArrayList<Integer> lista;
    private final int size;
    
    public CodificacionOrdinal(int size) {
        super(size);
        this.size = size;
        lista = new ArrayList<Integer>(size);
    }
    
    private void prepararLista() {
        lista.clear();
        for(int i = 0; i < size; i++) {
            lista.add(i);
        }
    }
    
    private int getOrdinal(List<Integer> genes, int index) {
        Integer gen = genes.get(index);
        int menores = 0;
        for(int i = 0; i < index; i++) {
            if(genes.get(i) < gen) {
                menores ++;
            }
        }
        return gen - menores;
    }
    
    protected void hacerOrdinal(List<Integer> genes) {
//        no esta muy claro que funcione la inversa (hacerCardinal) de una manera similar a esta
//        for(int i = size - 1; i >= 0; i--) {
//            genes.set(i, getOrdinal(genes, i));
//        }
        
//        menos eficiente pero mas facil de creerese que hace lo que debe
        prepararLista();
        for(int i = 0; i < size; i++) {
            int ordinal = lista.indexOf(genes.get(i));
            assert(ordinal >= 0) : "valor para "+genes.get(i)+" invalido (correcto = "+CromosomaPVC.isCorrecto(genes)+") ("+genes+")";
            lista.remove(ordinal); //borra lo que este en esa posicion, si hubiera sido un Integer borraria ese valor
            genes.set(i, ordinal);            
        }
    }
    
    protected void hacerCardinal(List<Integer> ordinales) {
        prepararLista();
        for(int i = 0; i < size; i++) {
            Integer ordinal = ordinales.get(i);
            Integer cardinal = lista.get(ordinal);
            lista.remove(cardinal);
            
            ordinales.set(i, cardinal);
        }
    }

    @Override
    protected void cruzar(CromosomaPVC p1, CromosomaPVC p2, CromosomaPVC h1, CromosomaPVC h2) {
        List<Integer> pg1 = p1.getGenes();
        List<Integer> pg2 = p2.getGenes();
        List<Integer> hg1 = h1.getGenes();
        List<Integer> hg2 = h2.getGenes();

        assert(CromosomaPVC.isCorrecto(pg1));
        hacerOrdinal(pg1);
        assert(CromosomaPVC.isCorrecto(pg2));
        hacerOrdinal(pg2);
        
        final int puntoCruce = (int) (Math.random() * size);
        for(int i = 0; i < puntoCruce; i++) {
            hg1.set(i, pg1.get(i));
            hg2.set(i, pg2.get(i));
        }
        for(int i = puntoCruce; i < size; i++) {
            hg1.set(i, pg2.get(i));
            hg2.set(i, pg1.get(i));
        }
        
        hacerCardinal(pg1);
        assert(CromosomaPVC.isCorrecto(pg1));
        hacerCardinal(pg2);
        assert(CromosomaPVC.isCorrecto(pg2));
        hacerCardinal(hg1);
        assert(CromosomaPVC.isCorrecto(hg1));
        hacerCardinal(hg2);
        assert(CromosomaPVC.isCorrecto(hg2));
    }
    
}
